extensions [table]

turtles-own [ home-pos ]
patches-own [ pellet-grid? ]  ;; true/false: is a pellet here initially?

breed [ pellets pellet ]
pellets-own [ powerup? ]

breed [ bonuses bonus ]
bonuses-own [ value countdown ]

breed [ pacmans pacman ]
pacmans-own  [ new-heading ]

breed [ ghosts ghost ]
ghosts-own  [ eaten? ]

globals [
  level         ;; current level
  score         ;; your score
  lives         ;; remaining lives
  extra-lives   ;; total number of extra lives you've won
  scared        ;; time until ghosts aren't scared (0 means not scared)
  level-over?   ;; true when a level is complete
  dead?         ;; true when Pac-Man is loses a life
  next-bonus-in ;; time until next bonus is created
  tool which-ghost ;; variables needed to properly load levels 4 and above.
  
  ;;;globals do agente
  comeuMigalha;;para saber se comeu migalha no estado anterior, 0 false, 1 true
  raioVisao ;o radio de visao do pacman a cada momento
  ;;para guardar os valores das direcoes correspondentes
  Nr
  Es
  Sl
  Os
  tabelaQ ;tabela que guarda os Qs
  ;PercentagemExploracao ;a percentagem de decisoes que vao ser tomadas com o objetivo de explorar o mundo
  ;tipoJogo ;jogo determinista ou indeterminista?
  
  hum
]

;;;;;;;;;;;;;;;;;;;;;;;;
;;; Setup Procedures ;;;
;;;;;;;;;;;;;;;;;;;;;;;;

to new ;;Observer Button
  set level 1
  load-map
  set score 0
  set lives 3
  set extra-lives 0
  set scared 0
  set level-over? false
  set hum 0
end






to load-map  ;; Observer Procedure
  reset-ticks
  ;; Filenames of Level Files
  ;let maps ["pacmap1.csv" "pacmap2.csv" "pacmap3.csv" "pacmap4.csv" "pacmap5.csv"] 
  let maps []
  if tipoJogo = "Determinista"
    [set maps ["pacmap1.csv" "pacmap2.csv" "pacmap3.csv" "pacmap4.csv" "pacmap5.csv"]]  
  if tipoJogo = "Indeterminista" 
    [set maps ["pacmap11.csv" "pacmap12.csv" "pacmap13.csv" "pacmap14.csv" "pacmap15.csv" ]]  
  set maps ["pacmap14.csv"]
  let current-score score
  let current-lives lives
  let current-extra-lives extra-lives
  let current-difficulty difficulty  
  ifelse ((level - 1) < length maps)
  [ import-world item (level - 1) maps
    set score current-score
    set lives current-lives
    set extra-lives current-extra-lives
    set difficulty current-difficulty
    set dead? false
    ask pacmans
    [ set home-pos list xcor ycor ]
    ask ghosts
    [ set home-pos list xcor ycor ]
  ]
  [ set level 1
    load-map ]
  ;;EDITADO - inicializar as variaveis globais
  inicializarVariaveisGlobais
end

;;EDITADO - Inicializar variaveis globais
to inicializarVariaveisGlobais
  ;as direcoes das acoes
  set Nr 0
  set Es 90
  set Sl 180
  set Os 270
  ;o raio de visao do pacman
  set raioVisao raioVisaoInicial
  ;a tabela onde se guarda os valores do Q
  set tabelaQ table:make
  lerficheiro
end


;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Runtime Procedures ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

 
to play
 
 if verboso = true [print ""]
 
  ;;para contar migalhas que faltam
  let migalhasTotal 0
   ;contar migalhas
    ask patches [
     if count pellets-here > 0[
      set migalhasTotal migalhasTotal + 1 
     ] 
    ]
 
  ;patch onde o pacman esta
  let patche 0
 
  ;Memorizar estado de onde vem
  let estadoOrigem table:make 
  ask pacmans [
   set estadoOrigem calculaEstadoV1 patch-here migalhasTotal
   set patche patch-here
  ]
  
  
  let estadoCorrente table:make
  
  ;; Only true at this point if you died and are trying to continue
  let acaoTomada 0
  if not dead? [ 
    
   move-pacman estadoOrigem
   
   ;contar migalhas
    set migalhasTotal 0
    ask patches [
     if count pellets-here > 0[
      set migalhasTotal migalhasTotal + 1 
     ] 
    ]
   ;calcular o novo estado apos mover-se
   ask pacmans [
    set acaoTomada heading    
    set patche patch-here 
    set estadoCorrente calculaEstadoV1 patche migalhasTotal
   ]
  ]
  
  
  
  
  update-bonuses
  if floor (score / 35000) > extra-lives
  [ set lives lives + 1
    set extra-lives extra-lives + 1 ]
  
  if dead?
  [ 
    ;calcular o estado de derrota
    ask pacmans [
     set estadoCorrente calculaEstadoV1 patch-here 0
     ;actualizar o valor do Q que o trouxe ate este estado
     actualizarQ estadoOrigem acaoTomada estadoCorrente patche
     set patche patch-here
    ]
    
    
    ;actualizar o valor de todos os Q(S,a) de todos os estados S=Derrota seja qual for a acao
    actualizarQ estadoCorrente 0 estadoCorrente patche
    actualizarQ estadoCorrente 90 estadoCorrente patche
    actualizarQ estadoCorrente 180 estadoCorrente patche
    actualizarQ estadoCorrente 270 estadoCorrente patche
    
    ;;Guarda tabela de estados
    escreverFicheiro
    
    ifelse lives = 0 [
    ; user-message word "Game Over!\nScore: " score 
      ;;stop
       new
    ]
    [ set lives lives - 1
      ;ifelse lives = 0
      ;[ user-message "You died!\nNo lives left." ]
      ;[ ifelse lives = 1
      ;  [ user-message "You died!\nOnly 1 life left." ]
      ;  [ user-message (word "You died!\nOnly " lives " lives left.") ]
      ;]
      ask pacmans
      [ setxy (item 0 home-pos) (item 1 home-pos)
        set heading 0
      ]
      ask ghosts
      [ setxy (item 0 home-pos) (item 1 home-pos)
        set heading 0
        set shape "ghost"
      ]
      set dead? false
    ]
    
    
    if nonStop = false [stop]
  ]
  ifelse level-over?
  [ 
    ;calcular o estado de vitoria
    ask pacmans [
     set estadoCorrente calculaEstadoV1 patch-here 0
     ;actualizar o valor do Q que o trouxe ate este estado
     actualizarQ estadoOrigem acaoTomada estadoCorrente patche
    ]
    ;calcular o estado de vitoria
    ask pacmans [
     set estadoOrigem calculaEstadoV1 patch-here 0
    ]
    ;actualizar o valor de todos os Q(S,a) de todos os estados S=Vitoria seja qual for a acao
    actualizarQ estadoOrigem 0 estadoOrigem patche
    actualizarQ estadoOrigem 90 estadoOrigem patche
    actualizarQ estadoOrigem 180 estadoOrigem patche
    actualizarQ estadoOrigem 270 estadoOrigem patche
    ;;Guarda tabela de estados
    escreverFicheiro
    
    ;user-message word "Level Complete!\nScore: " score  ;; \n means start a new line
    set level level + 1
    load-map
    set level-over? false
    if nonStop = false [stop] 
    ]
  [
    move-ghosts
    ;actualizar o valor do Q
    ask pacmans [
     set estadoCorrente calculaEstadoV1 patch-here migalhasTotal
    ]
    actualizarQ estadoOrigem acaoTomada estadoCorrente patche
    make-bonus
  ]
  ;;display
end

to move-pacman [estadoOrigem]  ;; Observer Procedure
tick
  ask pacmans
  [
    ;determina qual a accao a tomar
    let acao (determinarAccao estadoOrigem)
    let old-heading heading
    ;set heading new-heading
    set heading acao
    if [pcolor] of patch-ahead 1 != black
    [ set heading old-heading ]
    if [pcolor] of patch-ahead 1 = black
    [ fd 1 ]
;    fd 1
    consume
    ;; Level ends when all pellets are eaten
    if not any? pellets
    [ set level-over? true ]
    ;; Animation
    ifelse shape = "pacman"
    [ set shape "pacman open" ]
    [ set shape "pacman" ]
  ]
end

to consume  ;; Pacman Procedure
  ;; Consume Bonuses
  if any? bonuses-here
  [ set score score + sum [value] of bonuses-here
    ask bonuses-here [ die ] ]

  ;; Consume Pellets
  ifelse any? pellets-here
  [ ifelse [powerup?] of one-of pellets-here
    [ set score score + 500
      ;;EDITADO - para registar que comeuBolacha
      ;;set comeuBolacha? true
      set comeuMigalha 0
      set scared 40
      ask ghosts
      [ if not eaten?
        [ set shape "scared" ] ]
    ]
    ;;[ set score score + 100 ] EDITADO para preencher a variavel comeuMigalha
    [set score score + 100
      set comeuMigalha 1
      ;;set comeuBolacha? false
    ]
    ask pellets-here [ die ] ]
  
  ;;EDITADO - se nao comeu migalha altera a variaval comeuMigalha para false
  [
   set comeuMigalha 0 
   ;;set comeuBolacha? false
  ]

  ;; Ghosts
  if any? ghosts-here with [not eaten?]
  [ ifelse scared = 0
    [ set dead? true ]
    [ ask ghosts-here with [not eaten?]
      [ set eaten? true
        set shape "eyes"
        set score score + 500 ]
    ]
  ]
end

to update-bonuses  ;; Observer Procedure
  ask bonuses
  [ set heading heading + 13
    set countdown countdown - 1
    if countdown = 0
    [ die ] ]
end

to move-ghosts  ;; Observer Procedure
  ask ghosts
  [ ifelse eaten?
    [ if [pcolor] of patch-at 0 1 = gray
      [ set eaten? false
        set shape "ghost" ]
      return-home
    ]
    [ choose-heading ]
    fd 1
    ;;EDITADO - verificar se o pacman esta aqui
    if any? pacmans-here [
     set dead? true 
    ]
  ]
  
  if scared > 0
  [ set scared scared - 1
    ifelse scared < 10 and scared mod 2 = 0
    [ ask ghosts with [not eaten?]
      [ set shape "ghost" ] ]
    [ ask ghosts with [not eaten?]
      [ set shape "scared" ] ]
    if scared = 0
    [ ask ghosts with [not eaten?]
      [ set shape "ghost" ]
    ]
  ]
end

to return-home  ;; Ghosts Procedure
  let dirs clear-headings
  let new-dirs remove opposite heading dirs
  let home-dir 0
  if pcolor != gray
    [ set home-dir towards one-of patches with [pcolor = gray] ]
  let home-path 90 * round (home-dir / 90)

  if length new-dirs = 1
  [ set heading item 0 new-dirs ]
  if length new-dirs > 1
  [ ifelse position home-path new-dirs != false
    [ set heading home-path ]
    [ set heading one-of new-dirs ]
  ]
end

to choose-heading  ;; Ghosts Procedure
  let dirs clear-headings
  let new-dirs remove opposite heading dirs
  let pacman-dir false

  if length dirs = 1
  [ set heading item 0 dirs ]
  if length dirs = 2
  [ ifelse see-pacman item 0 dirs
    [ set pacman-dir item 0 dirs ]
    [ ifelse see-pacman item 1 dirs
      [ set pacman-dir item 1 dirs ]
      [ set heading one-of new-dirs ]
    ]
  ]
  if length dirs = 3
  [ ifelse see-pacman item 0 dirs
    [ set pacman-dir item 0 dirs ]
    [ ifelse see-pacman item 1 dirs
      [ set pacman-dir item 1 dirs ]
      [ ifelse see-pacman item 2 dirs
        [ set pacman-dir item 2 dirs ]
        [ set heading one-of new-dirs ]
      ]
    ]
  ]
  if length dirs = 4
  [ ifelse see-pacman item 0 dirs
    [ set pacman-dir item 0 dirs ]
    [ ifelse see-pacman item 1 dirs
      [ set pacman-dir item 1 dirs ]
      [ ifelse see-pacman item 2 dirs
        [ set pacman-dir item 2 dirs ]
        [ ifelse see-pacman item 3 dirs
          [ set pacman-dir item 3 dirs ]
          [ set heading one-of new-dirs ]
        ]
      ]
    ]
  ]
  if pacman-dir != false
  [ ifelse scared = 0
    [ set heading pacman-dir ]
    [ set dirs remove pacman-dir dirs
      set heading one-of dirs
    ]
  ]
end

to-report clear-headings ;; ghosts procedure
  let dirs []
  if [pcolor] of patch-at 0 1 != blue
  [ set dirs lput 0 dirs ]
  if [pcolor] of patch-at 1 0 != blue
  [ set dirs lput 90 dirs ]
  if [pcolor] of patch-at 0 -1 != blue
  [ set dirs lput 180 dirs ]
  if [pcolor] of patch-at -1 0 != blue
  [ set dirs lput 270 dirs ]
  report dirs
end

to-report opposite [dir]
  ifelse dir < 180
  [ report dir + 180 ]
  [ report dir - 180 ]
end

to-report see-pacman [dir] ;; ghosts procedure
  let saw-pacman? false
  let p patch-here
  while [[pcolor] of p = black]
  [ 
    ask p
    [ if any? pacmans-here
      [ set saw-pacman? true ]
      set p patch-at sin dir cos dir ;; next patch in direction dir
    ]
    ;; stop looking if you loop around the whole world
    if p = patch-here [ report saw-pacman? ]
  ]
  report saw-pacman?
end

to make-bonus ;; Observer Procedure
   ;;escolher um patch onde se vai colocar o bonus
  let bonus-patch one-of patches with [pellet-grid? and
                                                  not any? bonuses-here and
                                                  not any? pellets-here]
  
    if bonus-patch != nobody and random 20 < 1
    [ ask bonus-patch
      [ sprout-bonuses 1
        [ set shape "star"
          set heading 0
          set color random 14 * 10 + 5
          set value (random 10 + 1) * 100
          set countdown random 50 + 20 ] ]
      set next-bonus-in 5 + random 10 
    ] 
    
    ;;]
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Interface Procedures ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

to move-up
  ask pacmans [ set new-heading 0 ]
end

to move-right
  ask pacmans [ set new-heading 90 ]
end

to move-down
  ask pacmans [ set new-heading 180 ]
end

to move-left
  ask pacmans [ set new-heading 270 ]
end


; Copyright 2001 Uri Wilensky. All rights reserved.
; The full copyright notice is in the Information tab.




;;;;;;;;;;;;;;;;;;;;;;;;
;;; CODIGO DO AGENTE ;;;
;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: calcular recompensa de Vitoria e Derrota
;; calcula a recompensa associada a um estado
to-report calculaRecompensaV1 [estado]

  
  
  let recompensa 0
  
  ;;se comeu migalha adiciona recompensa, senao retira
  let comeuMig table:get estado "comeuMigalha"
  ifelse comeuMig = 1
  [
   set recompensa recompensa + recompensaMigalha
  ] 
  [
   set recompensa recompensa - recompensaMigalha
  ]
  
  ;;se tem migalhas a vista adicionar recompensa, senao retira
  ;ir buscar os ratios migalhas/distancia para escolher o melhor
  ;let migalhas []
  ;set migalhas fput (table:get estado "mN") migalhas
  ;set migalhas fput (table:get estado "mE") migalhas
  ;set migalhas fput (table:get estado "mS") migalhas  
  ;set migalhas fput (table:get estado "mO") migalhas  
  ;ifelse max migalhas > 0
  ;[
  ; set recompensa recompensa + max migalhas 
  ;]
  ;[
  ; set recompensa recompensa + 0
  ;]
  
  ;;para tornar o castigo de nao comerMigalha menos negativo.
  ;;ainda assim nunca sera positivo pois bestRatio e sempre menor que 1
  let bestRatio table:get estado "bestRatio"
  if bestRatio > 0
  [set recompensa recompensa + bestRatio * recompensaMigalha]
  
  ;se tem fantasmas a vista retira recompensa
  ;let fantasmas []
  ;set fantasmas fput (table:get estado "fN") fantasmas
  ;set fantasmas fput (table:get estado "fE") fantasmas
  ;set fantasmas fput (table:get estado "fS") fantasmas  
  ;set fantasmas fput (table:get estado "fO") fantasmas  
  ;ifelse min fantasmas > 0
  ;[
  ; set recompensa recompensa - min fantasmas
  ;]
  ;[
  ; set recompensa recompensa + 0
  ;]
  
  
  
  ; se alcancou derrota dah recompensa negativa
  if table:get estado "D" = 1 [
   set recompensa recompensaDerrota
  ]
  
  ;se alcancou a vitoria dah recompensa positiva
  if table:get estado "V" = 1 [
   set recompensa recompensaVitoria
  ]
  
  report precision recompensa 2
end





;; Obtem a representacao do Estado = (comeuMigalha, mN, dN, mE, dE, mS, dS, mO, dO) numa table
;;1 - Comeu migalha? (M) preenchido a 1 ou 0
;;2 - Ratio = Numero de Migalhas que v� em cada Dire��o) / Distancia que necessita de percorrer para apanhar todas as migalhas que v� em cada dire��o
;;3 - Fantasmas = a distancia aos fantasmas em cada direcao
;; patche: o patche onde queremos admitir que o pacman esta
;; migalhasTotal: o numero total de migalhas que ainda existem
to-report calculaEstadov1 [patche migalhasTotal]

  ;colocar mais uma caracteristica no estado para saber se so ha uma migalha

  ;;TO DO dividir o melhor Ratio pelo numero de migalhasTotal para ter a certeza que o ratio
  ;; da ultima migalha so e calculado quando o pacman esta mesmo perante a ultima
  ;; migalha

  ;;fazer tabela para guardar o estado e preenche-la
  let estado table:make
  
  ;;se morreu nao precisa calcular mais nada
  if dead? [
    table:put estado "D" 1
    table:put estado "V" 0
    table:put estado "comeuMigalha" 0
    ;table:put estado "mN" 0
    ;table:put estado "mE" 0
    ;table:put estado "mS" 0
    ;table:put estado "mO" 0
    table:put estado "bestDir" 0
    table:put estado "bestRatio" 0
    table:put estado "UltimaMigalha" 0
    table:put estado "fN" 0
    table:put estado "fE" 0
    table:put estado "fS" 0
    table:put estado "fO" 0
  ]

  if not dead?[
    table:put estado "D" 0
    ;se nao ha migalhas entao alcancou a vitoria e nao precisa de calcular mais nada
    ifelse migalhasTotal = 0 [
      table:put estado "V" 1
      table:put estado "comeuMigalha" 0
      ;table:put estado "mN" 0
      ;table:put estado "mE" 0
      ;table:put estado "mS" 0
      ;table:put estado "mO" 0
      table:put estado "bestDir" 0
      table:put estado "bestRatio" 0
      table:put estado "UltimaMigalha" 0
      table:put estado "fN" 0
      table:put estado "fE" 0
      table:put estado "fS" 0
      table:put estado "fO" 0
    ][
      table:put estado "V" 0
      table:put estado "comeuMigalha" comeuMigalha
      ;calcular os ratios de migalhas/distancia em cada direcao
      ;table:put estado "mN" contaMigalhasNaDirecao patche Nr raioVisao
      ;table:put estado "mE" contaMigalhasNaDirecao patche Es raioVisao
      ;table:put estado "mS" contaMigalhasNaDirecao patche Sl raioVisao
      ;table:put estado "mO" contaMigalhasNaDirecao patche Os raioVisao
      
      ;;meter os ratios de cada direcao numa lista
      let Direcoes (list 0 90 180 270)
      let listaRatios []
      foreach Direcoes [
        set listaRatios fput contaMigalhasNaDirecao patche ? raioVisao listaRatios
      ]
      set listaRatios reverse listaRatios
      
      ;ir buscar o maximo Ratio obtido
      let maxRatio max listaRatios
      let indiceMaxRatio 0
  
      ;;se houver mais que 1 maxRatio sorteia qual usa
      let indicesMaxRatios []
      ifelse contaOcorrencias maxRatio listaRatios > 1 [
        let indiceTemp 0
        ;procura os indices do MaxRatio e mete-os numa lista
        foreach listaRatios [
          if ? = maxRatio [
            set indicesMaxRatios fput indiceTemp indicesMaxRatios
          ]
          set indiceTemp indiceTemp + 1
        ]
        ;sorteia um dos indices
        random-seed new-seed
        set indiceMaxRatio one-of indicesMaxRatios
      ]
      [
        ;;se so houver um maxRatio ir buscar o seu indice
        set indiceMaxRatio (position maxRatio listaRatios)   
      ]
  
      ;colocar a direcao do melhor ratio no estado
      let bestDir item indiceMaxRatio Direcoes
      ;;se nao encontra migalhas perto aumenta o raio de visao
      ;;se encontra milhalhas perto diminui o raio de visao, mas nunca abaixo o raioVisaoIni
      ifelse maxRatio = 0 [
        set bestDir -1
        ;set raioVisao raioVisao * 2
        ;if raioVisao > 24 [set raioVisao 24]
      ][
       ;se o maxRatio nao for 0 entao incluir o numero de migalhas
       ;serve para diferenciar os estados em que pode comer a ultima migalha
       ;set maxRatio precision ((maxRatio / migalhasTotal) * 10) 2
       ;se maxRatio != 0 entao e porque ve migalhas logo pode diminuir o raio de visao
       ;if raioVisao > raioVisaoInicial [set raioVisao raioVisao - 1]
      ]
      table:put estado "BestDir" bestDir
      table:put estado "bestRatio" maxRatio
      ;;se so ha uma migalha no tabulueiro
      ifelse migalhasTotal = 1
        [table:put estado "UltimaMigalha" 1]
        [table:put estado "UltimaMigalha" 0]
      ;calcular a distancia aos fantasmas em cada direcao
      table:put estado "fN" calculaFantasmasNaDirecao patche Nr raioVisao
      table:put estado "fE" calculaFantasmasNaDirecao patche Es raioVisao
      table:put estado "fS" calculaFantasmasNaDirecao patche Sl raioVisao
      table:put estado "fO" calculaFantasmasNaDirecao patche Os raioVisao
    ]  
  ]
  
  report estado
end





;; imprime a representacao de um estado num formato facilmente legivel
to imprime-estadoV1 [estado]

  ;output-type "comeuMigalha?" output-show table:get estado "comeuMigalha"
  ;output-type "Migalhas/Distancia a Nr" output-show table:get estado "mN"
  ;output-type "Migalhas/Distancia a Es" output-show table:get estado "mE"
  ;output-type "Migalhas/Distancia a Sl" output-show table:get estado "mS"
  ;output-type "Migalhas/Distancia a Oe" output-show table:get estado "mO"
  
  ;output-show "--------------------------------"
end








;;conta o numero de migalhas que pode encontrar se seguir na Direcao dada, ate ao
;; limite de DistanciaMax 
;; patche: e o patch onde se encontra
to-report contaMigalhasNaDirecao [patche Direcao DistanciaMax]
  
  let MigalhasContadas 0
  ask patche [
   ;conta as migalhas que pode encontrar se seguir na Direcao dada
   let nextpatche patch-at-heading-and-distance Direcao 1
   let DirecaoDePartida ((Direcao + 180) mod 360)
   let caminhoPercorrido [] ;lista para memorizar os patches onde vai passando
   let distanciaPercorrida 0
   set migalhasContadas contaMigalhasRecursiva nextpatche DistanciaMax DistanciaPercorrida DirecaoDePartida caminhoPercorrido
   ;type "Direcao e Migalhas:" type Direcao type " " print migalhasContadas
  ]
  report migalhasContadas
end




;;calcula recursivamente o ratio (numero de migalhas / (distancia necessaria a percorrer + 1))
;; se seguir caminho em cada uma das direcoes possiveis, ate ao limite de DistanciaMax
;; patche: o primeiro patch do caminho que vai seguir
;; DistanciaMaxima: a distancia maxima que pode percorrer a partir deste patch
;; DistanciaPercorrida: a distancia que ja percorreu desde o sitio onde esta o pacman ate este 
;; patch; serve para saber a distancia que tem percorrer para comer todas as migalhas encontradas
;; DirecaoDeOndeVem: a direcao de onde veio para chegar a este patch, serve para impedir que volte
;; para tras, para o patch de onde veio
;; caminhoPercorrido: lista com o conjunto de patches por onde ja passou
to-report contaMigalhasRecursiva [patche DistanciaMax DistanciaPercorrida DirecaoDeOndeVem caminhoPercorrido]
  ;;;;;;;;;;;;;;; Bases da Recursao ;;;;;;;;;;;;;
  ;se a distancia se esgotou
  if DistanciaMax < 1 [
   report 0
  ]
  
  ;se encontrou parede
  if [pcolor] of patche != black [
   report 0
  ]
  
  ;se encontrou um fantasma ignora o resto do caminho
  let encontrouFantasma? false
  ask patche [
   if any? ghosts-here [
    set encontrouFantasma? true
   ]
  ]
  if encontrouFantasma? [report 0]
  
  ;se ja esteve no patche 
  foreach caminhoPercorrido [
    if patche = ? [
      report 0 
    ]
  ]
  
  ;;;;;;;;;;;;;; Passo da Recursao ;;;;;;;;;;;;;;;;
  
  ;;adicionar este patch a lista de patches percorridos
  set caminhoPercorrido fput patche caminhoPercorrido

  ;lista para guardar os resultados das varias chamadas recursivas a funcao
  ;para depois escolher o maior resultado
  let contagens []
  
  set DistanciaPercorrida DistanciaPercorrida + 1
  
  ;para guardar as coordenadas do patch
  let x 0
  let y 0
  let MigalhasContadas 0
  let DistanciaNecessaria 0
  ask patche [
   if any? pellets-here [
    set MigalhasContadas 1
    set DistanciaNecessaria DistanciaPercorrida
   ] 
   set x pxcor
   set y pycor
  ]
  
  ;contar o numero de migalhas que pode encontrar em cada direcao, excepto na direcao de onde veio
  let MigalhasTemp 0
  if DirecaoDeOndeVem != 0 [
   ;type x type "," type y type " dir em que vou contar migalhas:" show 0
   set MigalhasTemp contaMigalhasRecursiva (patch (x) (y + 1)) (DistanciaMax - 1) DistanciaPercorrida ((0 + 180) mod 360) caminhoPercorrido
   ;type x type "," type y type " MigalhasTemp" show MigalhasTemp
   set contagens fput MigalhasTemp contagens 
  ]
   
  if DirecaoDeOndeVem != 90 [
   ;type x type "," type y type " dir em que vou contar migalhas:" show 90
   set MigalhasTemp contaMigalhasRecursiva (patch (x + 1) (y)) (DistanciaMax - 1) DistanciaPercorrida ((90 + 180) mod 360) caminhoPercorrido
   ;type x type "," type y type " MigalhasTemp" show MigalhasTemp
   set contagens fput MigalhasTemp contagens 
  ]
    
  if DirecaoDeOndeVem != 180 [
   ;type x type "," type y type " dir em que vou contar migalhas:" show 180
   set MigalhasTemp contaMigalhasRecursiva (patch (x) (y - 1)) (DistanciaMax - 1) DistanciaPercorrida ((180 + 180) mod 360) caminhoPercorrido
   ;type x type "," type y type " MigalhasTemp" show MigalhasTemp
   set contagens fput MigalhasTemp contagens 
  ]
    
  if DirecaoDeOndeVem != 270 [
   ;type x type "," type y type " dir em que vou contar migalhas:" show 270
   set MigalhasTemp contaMigalhasRecursiva (patch (x - 1) (y)) (DistanciaMax - 1) DistanciaPercorrida ((270 + 180) mod 360) caminhoPercorrido
   ;type x type "," type y type " MigalhasTemp" show MigalhasTemp
   set contagens fput MigalhasTemp contagens 
  ]
   
  ;se a lista estiver vazia, i.e, se nao puder comer migalhas em 
  ;nenhuma direcao, retornar o valor de MigalhasContadas
  if length contagens = 0 [
   report MigalhasContadas
  ]
  
  ;type x type "," type y type " CONTAGENS:" show contagens
  report precision ((first (sort-by [?1 > ?2] contagens) + MigalhasContadas) / (DistanciaNecessaria + 1)) 2 ;;+1 para evitar divisoes por zero
end




;;calcula a distancia a que esta um fantasma se seguir na Direcao dada, ate ao
;; limite de DistanciaMax 
to-report calculaFantasmasNaDirecao [patche Direcao DistanciaMax]
  let distanciaPercorrida 0
  ask patche [
   ;conta as migalhas que pode encontrar se seguir na Direcao dada
   let nextpatche patch-at-heading-and-distance Direcao 1
   let DirecaoDePartida ((Direcao + 180) mod 360)
   set distanciaPercorrida calculaFantasmasRecursiva nextpatche DistanciaMax DirecaoDePartida
  ]
  report distanciaPercorrida
end


;;calcula recursivamente distancia necessaria a percorrer para encontrar um fantasma
;; se seguir caminho em cada uma das direcoes possiveis, ate ao limite de DistanciaMax
;; patche: o primeiro patch do caminho que vai seguir
;; DistanciaMaxima: a distancia maxima que pode percorrer a partir deste patch
;; DistanciaPercorrida: a distancia que ja percorreu desde o sitio onde esta o pacman ate este 
;; patch - serve para saber a distancia que tem percorrer para comer todas as migalhas encontradas
;; DirecaoDeOndeVem: a direcao de onde veio para chegar a este patch, serve para impedir que volte
;; para tras, para o patch de onde veio
to-report calculaFantasmasRecursiva [patche DistanciaMax DirecaoDeOndeVem]
  
  ;se a distancia se esgotou
  if DistanciaMax < 1 [
   report 0
  ]
  ;se encontrou parede
  if [pcolor] of patche != black [
   report 0
  ]
  ;se existe fantasma no patch para onde vai seguir retorna 1
  let x 0
  let y 0
  let temFantasma? false
  ask patche [
   if count ghosts-here > 0 [
    set temFantasma? true
   ]
   set x pxcor
   set y pycor 
  ]
  if temFantasma? 
    [report 1]
  
  ;lista para guardar os resultados das varias chamadas recursivas a funcao
  ;para depois escolher o menor resultado
  let contagens []
   
  ;calcula a distancia para encontrar um fantasma em cada direcao, excepto na direcao de onde veio
  let distTemp 0
  if DirecaoDeOndeVem != 0 [
   set distTemp calculaFantasmasRecursiva (patch (x) (y + 1)) (DistanciaMax - 1) ((0 + 180) mod 360)
   if distTemp > 0 [
    set distTemp distTemp + 1 
    set contagens fput distTemp contagens 
   ]
  ]
   
  if DirecaoDeOndeVem != 90 [
   set distTemp calculaFantasmasRecursiva (patch (x + 1) (y)) (DistanciaMax - 1) ((90 + 180) mod 360)
   if distTemp > 0 [
    set distTemp distTemp + 1 
    set contagens fput distTemp contagens 
   ]
  ]
      
  if DirecaoDeOndeVem != 180 [
   set distTemp calculaFantasmasRecursiva (patch (x) (y - 1)) (DistanciaMax - 1) ((180 + 180) mod 360)
   if distTemp > 0 [
    set distTemp distTemp + 1 
    set contagens fput distTemp contagens 
   ]
  ]   
    
  if DirecaoDeOndeVem != 270 [
   set distTemp calculaFantasmasRecursiva (patch (x - 1) (y)) (DistanciaMax - 1) ((270 + 180) mod 360)
   if distTemp > 0 [
    set distTemp distTemp + 1 
    set contagens fput distTemp contagens 
   ]
  ]
  
  ;type "contagens:" print contagens
  
  if length contagens = 0 [
   report 0 
  ]
  
  ;type x type "," type y type " CONTAGENS:" show contagens
  ;devolve a menor distancia ate um fantasma
  report first (sort-by [?2 > ?1] contagens)
end








;;determina qual o new-heading a tomar pelo pacman
to-report determinarAccao [estadoOrigem]

  if verboso = true [print "Ponderar as acoes:"]

  ;;obter todas as acoes possiveis e gerar as chaves do Q [acao Estado]
  let patche patch-here
  let #accoes (list 0 90 180 270)
  let listaChavesQ []
  foreach #accoes [
   let patcheTemp patch-at-heading-and-distance ? 1
   if [pcolor] of patcheTemp = black [
     set listaChavesQ fput converteEstadoEacaoParaChaveQ estadoOrigem ? listaChavesQ
     if verboso = true [print ?]
   ]
  ]
  
  ;obter todos os valores de Q(S,a) para todas as acoes possiveis
  let listaValoresQ []
  foreach listaChavesQ [
    ifelse table:has-key? tabelaQ ? [
      set listaValoresQ fput table:get tabelaQ ? listaValoresQ
      if verboso = true [type "AcaoEstado e ValorQ:" type ? type " " print table:get tabelaQ ?]
    ][
      set listaValoresQ fput 0 listaValoresQ
      if verboso = true [type "AcaoEstado e ValorQ:" type ? print " 0" ]
    ]
   
  ]
  set listaValoresQ reverse listaValoresQ 
  
  ;ir buscar o maximo Q(S,a)
  let maxQ max listaValoresQ
  let indiceMaxQ 0
  
  ;;se houver mais que 1 maxQ sorteia qual usa
  let indicesMaxQ []
  ifelse contaOcorrencias maxQ listaValoresQ > 1 [
    let indiceTemp 0
    ;procura os indices do MaxQ e mete-os numa lista
    foreach listaValoresQ [
     if ? = maxQ [
       set indicesMaxQ fput indiceTemp indicesMaxQ
     ]
     set indiceTemp indiceTemp + 1
    ]
    ;sorteia um dos indices
    random-seed new-seed
    set indiceMaxQ one-of indicesMaxQ
  ]
  [
   ;;se so houver um maxQ ir buscar o seu indice
   set indiceMaxQ (position maxQ listaValoresQ)   
  ]
  
  ;definir a acao a tomar de acordo com o indice escolhido
  let chaveMaxQ item indiceMaxQ listaChavesQ
  let acaoMax first chaveMaxQ
  
  ;set new-heading acaoMax
  
  ;;Greedy
  let acao 0
  set #accoes obterAccoesPossiveis
  random-seed new-seed 
  ifelse( (random 100) + 1 <= PercentagemExploracao) [
   let a item (random length #accoes) #accoes 
   set acao  a
  ]
  [
   set acao acaoMax
  ]
  
  if verboso = true [type "Accao Tomada:" show acao]
  
  report acao
end







;; count the number of occurrences of an item in a list
to-report contaOcorrencias [x the-list]
  report reduce
    [ifelse-value (?2 = x) [?1 + 1] [?1]] (fput 0 the-list)
end


;; devolve uma lista com todas as direcoes que o pacman pode tomar
to-report obterAccoesPossiveis
  let dirs []
  ask pacmans [
    if [pcolor] of patch-at 0 1 = black
    [ set dirs fput 0 dirs ]
    if [pcolor] of patch-at 1 0 = black
    [ set dirs fput 90 dirs ]
    if [pcolor] of patch-at 0 -1 = black
    [ set dirs fput 180 dirs ]
    if [pcolor] of patch-at -1 0 = black
    [ set dirs fput 270 dirs ]
  ]
  report dirs
end

;;devolve o numero de estados existentes na tabela dos Qs
to-report numEstadosConhecidos
  report length table:Keys tabelaQ
end




;;;;;;;;;;;;;;;;;;
;;; ALGORITMO Q ;;
;;;;;;;;;;;;;;;;;;


; funcao que verifica o tipo de jogo que esta a ser jogado e chama
; a funcao actualizarQ-tipoDeJogo de acordo com o tipo de jogo
to actualizarQ [estadoOrigem accao estadoCorrente patche]
  if tipoJogo = "Determinista"
    [actualizarQ-Determ estadoOrigem accao estadoCorrente patche]
  if tipoJogo = "Indeterminista"
    [actualizarQ-Indeterm estadoOrigem accao estadoCorrente patche]
end



;;actualiza o valor do Q, dado um estado e uma accao
;; Q: tabela com todos os valores de Q(S,a) conhecidos
;; estado: o estado, em formato de tabela
;; accao: a accao (nao e bem a accao e a posicao da accao na lista de acoes possiveis)
;; accoes: lista de todas as accoes possiveis
;; patche: o patche onde queremos admitir que o pacman est� ie, o patch do estadoCorrente
to actualizarQ-Determ [estadoOrigem accao estadoCorrente patche]
  
  ;gera a chave do Q
  let #estadoAcao converteEstadoEacaoParaChaveQ estadoOrigem accao
  
  ;;dado o estadoCorrente quais as accoes possiveis a partir dele?
  let listaChavesQsSeguintes []
  let #accoes [0 90 180 270]
  foreach #accoes [
      ask patche [
       let patcheTemp patch-at-heading-and-distance ? 1
       if [pcolor] of patcheTemp = black[
        set listaChavesQsSeguintes fput converteEstadoEacaoParaChaveQ estadoCorrente ? listaChavesQsSeguintes
       ]
      ] 
     ]
  
  ;;escolher o maximoQseguinte Q(S',a')
  let listaValoresQs []
  foreach listaChavesQsSeguintes [
   ifelse table:has-key? tabelaQ ? [
    set listaValoresQs fput table:get tabelaQ ? listaValoresQs
    if verboso = true [type "Q seguinte e ValorQ:" type ? type " " show first listaValoresQs]
   ][
    if verboso = true [type "Q seguinte e ValorQ:" type ? type " " show 0]
   ]
  ]
  ;se nao houver nenhum Q(S',a') seguinte o maxQseguinte fica logo a zero
  let maxQseguinte 0
  if length listaValoresQs != 0 [
   set maxQseguinte max listaValoresQs    
  ]
  
  
  ;Calcula valor Q(S,a) = R(S) + gamma * maxQseguinte 
  let Qtemp calculaRecompensaV1 estadoOrigem
  ;let Qtemp calculaRecompensaV1 estadoCorrente
  if verboso = true [type "Recompensa deste Estado:" print Qtemp]
  set Qtemp precision (Qtemp + gamma * maxQseguinte) 3
  
  ;Actualiza o valor de Q
  ifelse table:get estadoOrigem "V" = 1
    [table:put tabelaQ #estadoAcao recompensaVitoria]
    [ifelse table:get estadoOrigem "D" = 1
       [table:put tabelaQ #estadoAcao recompensaDerrota]
       [table:put tabelaQ #estadoAcao Qtemp]
    ]
  
  if verboso = true [type "Q(S, a) e Valor: " type #estadoAcao type " " show table:get tabelaQ #estadoAcao]
end






;; Q(S,a) = (1-alpha)Q(S,a) + alpha (R(S,a) + gamma max Q(S',a'))
to actualizarQ-Indeterm [estadoOrigem accao estadoCorrente patche]
  
  ;gera a chave do Q  
  let #estadoAcao converteEstadoEacaoParaChaveQ estadoOrigem accao
  
  ;;dado o estadoCorrente quais as accoes possiveis a partir dele?
  let listaChavesQsSeguintes []
  let #accoes [0 90 180 270]
  foreach #accoes [
      ask patche [
       let patcheTemp patch-at-heading-and-distance ? 1
       if [pcolor] of patcheTemp = black[
        set listaChavesQsSeguintes fput converteEstadoEacaoParaChaveQ estadoCorrente ? listaChavesQsSeguintes
       ]
      ] 
     ]
  
  ;;escolher o maximoQseguinte Q(S',a')
  let listaValoresQs []
  foreach listaChavesQsSeguintes [
   ifelse table:has-key? tabelaQ ? [
    set listaValoresQs fput table:get tabelaQ ? listaValoresQs
    if verboso = true [type "Q seguinte e ValorQ:" type ? type " " show first listaValoresQs]
   ][
    if verboso = true [type "Q seguinte e ValorQ:" type ? type " " show 0]
   ]
  ]
  ;se nao houver nenhum Q(S',a') seguinte o maxQseguinte fica logo a zero
  let maxQseguinte 0
  if length listaValoresQs != 0 [
   set maxQseguinte max listaValoresQs    
  ]
  
  
  ;calcula Q(S,a) = (1-alpha)Q(S,a) + alpha (R(S,a) + gamma max Q(S',a'))
  let Qanterior 0
  if table:has-key? tabelaQ #estadoAcao [
    set Qanterior table:get tabelaQ #estadoAcao
  ]
  let Qtemp (1 - alpha) * Qanterior
  
  let r calculaRecompensaV1 estadoOrigem
  ;let r calculaRecompensaV1 estadoCorrente
  set Qtemp Qtemp + (alpha * (r + gamma * maxQseguinte))
  set Qtemp precision Qtemp 3
  
  if verboso = true [type "Recompensa deste Estado:" print r]
  
  ;Actualiza o valor de Q
  ifelse table:get estadoOrigem "V" = 1
    [table:put tabelaQ #estadoAcao recompensaVitoria]
    [ifelse table:get estadoOrigem "D" = 1
       [table:put tabelaQ #estadoAcao recompensaDerrota]
       [table:put tabelaQ #estadoAcao Qtemp]
    ]
  
  if verboso = true [type "Q(S, a) e Valor: " type #estadoAcao type " " show table:get tabelaQ #estadoAcao]
  
end






;Converte um estado e uma acao para um formato correspondente
;as chaves da tabelaQ
to-report converteEstadoEacaoParaChaveQ [#estado #accao]

  ;criar uma lista a partir da tabela que fica na forma [[key1, value1], ..., [keyN, valueN]]
  let #estadoKeyValue table:to-list #estado
  
  ;por cada elemento da lista ir buscar o value
  let #estadoAcao []
  foreach #estadoKeyValue [
    set #estadoAcao fput (item 1 ?) #estadoAcao
  ]
  
  ;adicionar a acao a chave
  set #estadoAcao fput #accao #estadoAcao
  
  report #estadoAcao
end




to escreverFicheiro

  
  if (file-exists? "memoria.txt") [ file-close file-delete "memoria.txt" ]
    
  file-open "memoria.txt"
    
  foreach( table:keys tabelaQ)
  [
    file-print ?
    file-print table:get tabelaQ ?
  ]
 
  file-close
end

to lerFicheiro

  
  table:clear tabelaQ
  
  if (file-exists? "memoria.txt") [  
  
    file-open "memoria.txt"
  
    while[not file-at-end? ]
    [
       let chaves read-from-string file-read-line
       let valores read-from-string file-read-line
     
       table:put tabelaQ chaves valores
  ]

  file-close
  ]
  
end












;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;; lixo ;;;;;;;;;;;;;;;;;;;;;;;;
























@#$#@#$#@
GRAPHICS-WINDOW
243
10
694
482
10
10
21.0
1
10
1
1
1
0
1
0
1
-10
10
-10
10
0
0
0
ticks

MONITOR
395
484
505
529
Score
score
0
1
11

BUTTON
42
150
191
183
Automático
play
T
1
T
OBSERVER
NIL
NIL
NIL
NIL

MONITOR
505
484
560
529
Level
level
0
1
11

MONITOR
560
484
615
529
Lives
lives
0
1
11

SLIDER
395
538
615
571
difficulty
difficulty
0
7
4
1
1
NIL
HORIZONTAL

BUTTON
244
535
341
568
Memorizar
escreverFicheiro
NIL
1
T
OBSERVER
NIL
NIL
NIL
NIL

SLIDER
16
261
216
294
PercentagemExploracao
PercentagemExploracao
0
100
0
1
1
%
HORIZONTAL

SLIDER
16
338
215
371
raioVisaoInicial
raioVisaoInicial
8
24
20
1
1
NIL
HORIZONTAL

SLIDER
16
379
215
412
gamma
gamma
0.1
1
1
0.1
1
NIL
HORIZONTAL

SWITCH
16
593
126
626
verboso
verboso
1
1
-1000

SWITCH
16
633
126
666
nonStop
nonStop
1
1
-1000

BUTTON
43
76
191
109
Novo Jogo
new
NIL
1
T
OBSERVER
NIL
NIL
NIL
NIL

TEXTBOX
49
10
189
28
PREPARAR NOVO JOGO
12
0.0
1

TEXTBOX
96
131
154
149
JOGAR
12
0.0
1

BUTTON
42
187
192
220
Passo-a-Passo
set verboso true\nplay\nset verboso false
NIL
1
T
OBSERVER
NIL
NIL
NIL
NIL

TEXTBOX
75
319
167
337
PARAMETROS
12
0.0
1

SLIDER
16
462
215
495
recompensaVitoria
recompensaVitoria
10
1000
100
10
1
NIL
HORIZONTAL

SLIDER
16
505
216
538
recompensaDerrota
recompensaDerrota
-1000
-10
-100
10
1
NIL
HORIZONTAL

SLIDER
16
548
216
581
recompensaMigalha
recompensaMigalha
1
10
1
1
1
NIL
HORIZONTAL

MONITOR
243
484
387
529
Estados Conhecidos
numEstadosConhecidos
0
1
11

CHOOSER
43
27
191
72
tipoJogo
tipoJogo
"Determinista" "Indeterminista"
0

SLIDER
16
420
215
453
alpha
alpha
0.1
1
1
0.1
1
NIL
HORIZONTAL

TEXTBOX
12
241
233
259
ALGORITMO DE ESCOLHA DA ACAO
12
0.0
1

@#$#@#$#@
WHAT IS IT?
-----------
This is the classic arcade game, Pac-Man.  The game involves navigating Pac-Man through a maze.  Your objective is that Pac-Man eat all of the pellets (white circles), while avoiding the ghosts that pursue him.

If a ghost ever catches Pac-Man then Pac-Man is defeated.  If this occurs, the level will reset, but this will happen only if Pac-Man still has some lives remaining. (The pellets already collected on the level remain collected.)

However, when Pac-Man eats a Power-Pellet (large white circle) he can turn the tide, and the ghosts will turn scared and flee from him, for with the power of the Power-Pellet, Pac-Man can eat the ghosts!  Once a ghost is eaten it will return to its base, where it is born again, immune to the Power-Pellet until Pac-Man can find a new one to consume.  Pac-Man had better do just that, because unfortunately, the power of the Power-Pellet does not last forever, and will begin to wear off over time. (You will see the ghosts start to flash back to their normal appearance during the last few seconds of the Power-Pellet's effectiveness.)

Finally, occasionally a bonus (rotating star) will appear in the maze.  This bonus gives Pac-Man extra points if he eats it, but it will disappear if Pac-Man doesn't get it within a limited amount of time.


HOW TO USE IT
-------------
Monitors
-- SCORE shows your current score.  You get points for collecting pellets, eating ghosts, and collecting bonuses.  You will get an extra life after every 35,000 points.
-- LEVEL shows your current level.  Each level has a different map, if you complete all the maps, it will loop back to the first map and continue.
-- LIVES shows how many extra lives you have remaining.  If you are defeated by a ghost when this is at 0, the game is over.

Sliders
-- DIFFICULTY controls the speed of the game.  Lower numbers make both the ghosts and Pac-Man move slowly, giving you more time to react as you play.

Buttons
-- NEW sets up a new game on level 1, with 3 lives, and a score of 0.
-- PLAY begins the game.  The game will pause after each level, so you will need to hit PLAY again after each level to continue.

Controls
-- UP, DOWN, LEFT, RIGHT control the direction Pac-Man moves.


THINGS TO NOTICE
----------------
If you go off the edge of the maze you will wrap around to the other side.

Identifying Things in the Maze:
-- Yellow Circle with a mouth:  This is Pac-Man - you.
-- White Circles:               These are Pellets - Collect all of these (including the Power-Pellets) to move on to the next level.
-- Large White Circles:         These are Power-Pellets - They allow you to eat the Ghosts for a limited ammount of time.
-- Blue Squares:                These are the walls of the maze - Neither Pac-Man nor the Ghosts can move through the walls.
-- Gray Squares:                These are the Ghost Gates - Only Ghosts can move through them, and if they do so after having been eaten they will be healed.
-- Rotating Colored Stars:      These are Bonus Stars - They give you extra points when you eat them.
-- Colorful Ghost with Eyes:    These are the active Ghosts - Watch out for them!
-- Blue Ghost Shape:            These are the scared Ghosts - Eat them for Extra Points!
-- Two Small Eyes:              These are the Ghosts after they've been eaten - They will not affect you, and you can't eat them again, so just ignore them, but try not to be near its base when it gets back there.

Scoring System
-- Eat a Pellet:       100 Points
-- Eat a Power-Pellet: 500 Points
-- Eat a Scared Ghost: 500 Points
-- Eat a Bonus Star:   100-1000 Points (varies)


THINGS TO TRY
-------------
Beat your Highest Score.

Can you write an automated program for Pac-Man that will get him safely through the maze and collect all the pellets?


EXTENDING THE MODEL
-------------------
Think of other power-ups or bonuses that might be fun to have and make them appear randomly in the maze.

Add new enemies that behave differently from the ghosts.


NETLOGO FEATURES
-----------------
This model makes use of breeds, create-<breed>, every, and user-message.

The "import-world" command is used to read in the different maze configurations (levels).


HOW TO CITE
-----------
If you mention this model in an academic publication, we ask that you include these citations for the model itself and for the NetLogo software:
- Wilensky, U. (2001).  NetLogo Pac-Man model.  http://ccl.northwestern.edu/netlogo/models/Pac-Man.  Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
- Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.

In other publications, please use:
- Copyright 2001 Uri Wilensky. All rights reserved. See http://ccl.northwestern.edu/netlogo/models/Pac-Man for terms of use.


COPYRIGHT NOTICE
----------------
Copyright 2001 Uri Wilensky. All rights reserved.

Permission to use, modify or redistribute this model is hereby granted, provided that both of the following requirements are followed:
a) this copyright notice is included.
b) this model will not be redistributed for profit without permission from Uri Wilensky. Contact Uri Wilensky for appropriate licenses for redistribution for profit.

This model was created as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227.

@#$#@#$#@
default
true
0
Polygon -7500403 true true 150 5 40 250 150 205 260 250

airplane
true
0
Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15

arrow
true
0
Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150

box
false
0
Polygon -7500403 true true 150 285 285 225 285 75 150 135
Polygon -7500403 true true 150 135 15 75 150 15 285 75
Polygon -7500403 true true 15 75 15 225 150 285 150 135
Line -16777216 false 150 285 150 135
Line -16777216 false 150 135 15 75
Line -16777216 false 150 135 285 75

bug
true
0
Circle -7500403 true true 96 182 108
Circle -7500403 true true 110 127 80
Circle -7500403 true true 110 75 80
Line -7500403 true 150 100 80 30
Line -7500403 true 150 100 220 30

butterfly
true
0
Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
Circle -16777216 true false 135 90 30
Line -16777216 false 150 105 195 60
Line -16777216 false 150 105 105 60

car
false
0
Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
Circle -16777216 true false 180 180 90
Circle -16777216 true false 30 180 90
Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
Circle -7500403 true true 47 195 58
Circle -7500403 true true 195 195 58

circle
false
0
Circle -7500403 true true 45 45 210

circle 2
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240

cow
false
0
Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
Polygon -7500403 true true 73 210 86 251 62 249 48 208
Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123

cylinder
false
0
Circle -7500403 true true 0 0 300

dot
false
0
Circle -7500403 true true 90 90 120

eyes
false
0
Circle -1 true false 62 75 57
Circle -1 true false 182 75 57
Circle -16777216 true false 79 93 20
Circle -16777216 true false 196 93 21

face happy
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240

face neutral
false
0
Circle -7500403 true true 8 7 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Rectangle -16777216 true false 60 195 240 225

face sad
false
0
Circle -7500403 true true 8 8 285
Circle -16777216 true false 60 75 60
Circle -16777216 true false 180 75 60
Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183

fish
false
0
Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
Circle -16777216 true false 215 106 30

flag
false
0
Rectangle -7500403 true true 60 15 75 300
Polygon -7500403 true true 90 150 270 90 90 30
Line -7500403 true 75 135 90 135
Line -7500403 true 75 45 90 45

flower
false
0
Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
Circle -7500403 true true 85 132 38
Circle -7500403 true true 130 147 38
Circle -7500403 true true 192 85 38
Circle -7500403 true true 85 40 38
Circle -7500403 true true 177 40 38
Circle -7500403 true true 177 132 38
Circle -7500403 true true 70 85 38
Circle -7500403 true true 130 25 38
Circle -7500403 true true 96 51 108
Circle -16777216 true false 113 68 74
Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240

ghost
false
0
Circle -7500403 true true 61 30 179
Rectangle -7500403 true true 60 120 240 232
Polygon -7500403 true true 60 229 60 284 105 239 149 284 195 240 239 285 239 228 60 229
Circle -1 true false 81 78 56
Circle -16777216 true false 99 98 19
Circle -1 true false 155 80 56
Circle -16777216 true false 171 98 17

house
false
0
Rectangle -7500403 true true 45 120 255 285
Rectangle -16777216 true false 120 210 180 285
Polygon -7500403 true true 15 120 150 15 285 120
Line -16777216 false 30 120 270 120

leaf
false
0
Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195

line
true
0
Line -7500403 true 150 0 150 300

line half
true
0
Line -7500403 true 150 0 150 150

pacman
true
0
Circle -7500403 true true 0 0 300
Polygon -16777216 true false 105 -15 150 150 195 -15

pacman open
true
0
Circle -7500403 true true 0 0 300
Polygon -16777216 true false 270 -15 149 152 30 -15

pellet
true
0
Circle -7500403 true true 105 105 92

pentagon
false
0
Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120

person
false
0
Circle -7500403 true true 110 5 80
Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
Rectangle -7500403 true true 127 79 172 94
Polygon -7500403 true true 195 90 240 150 225 180 165 105
Polygon -7500403 true true 105 90 60 150 75 180 135 105

plant
false
0
Rectangle -7500403 true true 135 90 165 300
Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90

scared
false
0
Circle -13345367 true false 61 30 179
Rectangle -13345367 true false 60 120 240 232
Polygon -13345367 true false 60 229 60 284 105 239 149 284 195 240 239 285 239 228 60 229
Circle -16777216 true false 81 78 56
Circle -16777216 true false 155 80 56
Line -16777216 false 137 193 102 166
Line -16777216 false 103 166 75 194
Line -16777216 false 138 193 171 165
Line -16777216 false 172 166 198 192

square
false
0
Rectangle -7500403 true true 30 30 270 270

square 2
false
0
Rectangle -7500403 true true 30 30 270 270
Rectangle -16777216 true false 60 60 240 240

star
false
0
Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108

target
false
0
Circle -7500403 true true 0 0 300
Circle -16777216 true false 30 30 240
Circle -7500403 true true 60 60 180
Circle -16777216 true false 90 90 120
Circle -7500403 true true 120 120 60

tree
false
0
Circle -7500403 true true 118 3 94
Rectangle -6459832 true false 120 195 180 300
Circle -7500403 true true 65 21 108
Circle -7500403 true true 116 41 127
Circle -7500403 true true 45 90 120
Circle -7500403 true true 104 74 152

triangle
false
0
Polygon -7500403 true true 150 30 15 255 285 255

triangle 2
false
0
Polygon -7500403 true true 150 30 15 255 285 255
Polygon -16777216 true false 151 99 225 223 75 224

truck
false
0
Rectangle -7500403 true true 4 45 195 187
Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
Rectangle -1 true false 195 60 195 105
Polygon -16777216 true false 238 112 252 141 219 141 218 112
Circle -16777216 true false 234 174 42
Rectangle -7500403 true true 181 185 214 194
Circle -16777216 true false 144 174 42
Circle -16777216 true false 24 174 42
Circle -7500403 false true 24 174 42
Circle -7500403 false true 144 174 42
Circle -7500403 false true 234 174 42

turtle
true
0
Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99

wheel
false
0
Circle -7500403 true true 3 3 294
Circle -16777216 true false 30 30 240
Line -7500403 true 150 285 150 15
Line -7500403 true 15 150 285 150
Circle -7500403 true true 120 120 60
Line -7500403 true 216 40 79 269
Line -7500403 true 40 84 269 221
Line -7500403 true 40 216 269 79
Line -7500403 true 84 40 221 269

x
false
0
Polygon -7500403 true true 270 75 225 30 30 225 75 270
Polygon -7500403 true true 30 75 75 30 270 225 225 270

@#$#@#$#@
NetLogo 4.1.3
@#$#@#$#@
new
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
@#$#@#$#@
default
0.0
-0.2 0 0.0 1.0
0.0 1 1.0 0.0
0.2 0 0.0 1.0
link direction
true
0
Line -7500403 true 150 150 90 180
Line -7500403 true 150 150 210 180

@#$#@#$#@
0
@#$#@#$#@
